package game.cellmap;

import game.GraphicUtil;
import game.Logger;
import game.Position;
import game.cellsize.ICellSizeChangeListener;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CellMap
{
    protected static boolean              KEYLISTENER_ENABLED     = false;
    
    private int[]                         SIZES                   = new int[10];
    
    private short                         cellSize;
    private List<ICellSizeChangeListener> cellSizeChangeListeners = new ArrayList<ICellSizeChangeListener>();
    
    private Position                      mapSize;
    
    public CellMap(boolean keyListenerEnabled, int cellSize)
    {
        KEYLISTENER_ENABLED = keyListenerEnabled;
        setCellSizes(10, 20, 30, 40, 50, 60, 70, 80, 90, 100);
        setCellSize(cellSize);
    }
    
    public CellMap(boolean keyListenerEnabled)
    {
        this(keyListenerEnabled, 16);
    }
    
    public CellMap(int cellSize)
    {
        this(false, cellSize);
    }
    
    public void setCellSizes(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, int x9, int x0)
    {
        SIZES = new int[] { x0, x1, x2, x3, x4, x5, x6, x7, x8, x9 };
    }
    
    protected synchronized void setCellSize(int cellSize)
    {
        if (this.cellSize != cellSize)
        {
            this.cellSize = (short) cellSize;
            System.out.println("NEW CELLSIZE: " + cellSize);
            fireCellSizeChanged(cellSize);
        }
    }
    
    public short getCellSize()
    {
        return cellSize;
    }
    
    public void addCellSizeChangeListener(ICellSizeChangeListener cellSizeChangeListener)
    {
        cellSizeChangeListeners.add(cellSizeChangeListener);
    }
    
    public void removeCellSizeChangeListener(ICellSizeChangeListener cellSizeChangeListener)
    {
        cellSizeChangeListeners.remove(cellSizeChangeListener);
    }
    
    private void fireCellSizeChanged(int cellSize)
    {
        synchronized(cellSizeChangeListeners)
        {
            for (ICellSizeChangeListener cellSizeChangeListener : cellSizeChangeListeners)
            {
                cellSizeChangeListener.cellSizeChanged(cellSize);
            }
        }
    }
    
    public Position getMapSize()
    {
        return mapSize;
    }
    
    public void setMapSize(Position size)
    {
        this.mapSize = size;
        System.out.println("NEW MAP-SIZE: " + getMapSize().getWidth() + "/" + getMapSize().getHeight());
        System.out.println("NEW CELLMAP-SIZE: " + getMapSize().getWidth() * cellSize + "/" + getMapSize().getHeight() * cellSize);
    }
    
    public Position getCellMapSize()
    {
        return new Position(getMapSize().getWidth() * getCellSize(), getMapSize().getHeight() * getCellSize());
    }
    
    public int calculateIndex(Position position)
    {
        return calculateIndex(position.getX(), position.getY(), getMapSize());
    }
    
    public int calculateIndex(Position position, Position size)
    {
        return calculateIndex(position.getX(), position.getY(), size);
    }
    
    public int calculateIndex(int x, int y)
    {
        return calculateIndex(x, y, getMapSize());
    }
    
    public static int calculateIndex(int x, int y, Position size)
    {
        if (x < 0 || x > size.getWidth() || y < 0 || y > size.getHeight())
        {
            return -1;
        }
        int index = (size.getWidth() * y) + x;
        return index;
    }
    
    public Position calculatePosition(int index)
    {
        return calculatePosition(index, getMapSize());
    }
    
    public static Position calculatePosition(int index, Position size)
    {
        int x = 0;
        int y = 0;
        // find y
        y = index / size.getX();
        x = index - (y * size.getX());
        return new Position(x, y);
    }
    
    public Position calcMaxSize(Position windowSize)
    {
        int width = windowSize.getWidth();
        if (width % cellSize != 0)
        {
            width -= width % cellSize;
        }
        width /= cellSize;
        int height = windowSize.getHeight();
        if (height % cellSize != 0)
        {
            height -= height % cellSize;
        }
        height /= cellSize;
        return new Position(width, height);
    }
    
    public Position calcCoord(java.awt.Point p)
    {
        return calcCoord(new Position(p.x, p.y));
    }
    
    public Position calcCoord(Position p)
    {
        Position mapSize = getCellMapSize();
        int x = -1;
        int y = -1;
        if (p.getX() <= mapSize.getWidth() && p.getY() <= mapSize.getHeight())
        {
            x = (int) (p.getX() / cellSize);
            y = (int) (p.getY() / cellSize);
        }
        return new Position(x, y);
    }
    
    public void fillRect(Graphics g, Position position, Color color)
    {
        fillRect(g, position.getX(), position.getY(), color);
    }
    
    public void fillRect(Graphics g, int x, int y, Color color)
    {
        GraphicUtil.fillRect(g, x * cellSize, y * cellSize, cellSize, cellSize, color);
    }
    
    public void drawRect(Graphics g, Position position, Color color)
    {
        drawRect(g, position.getX(), position.getY(), color);
    }
    
    public void drawRect(Graphics g, int x, int y, Color color)
    {
        drawRect(g, x, y, color, 0);
    }
    
    public void drawRect(Graphics g, int x, int y, Color color, int border)
    {
        GraphicUtil.drawRect(g, (x * cellSize) + border, (y * cellSize) + border, cellSize, cellSize, color);
    }
    
    public void drawString(Graphics g, String s, int fontSize, int x, int y, Color color)
    {
        g.setColor(color);
        g.setFont(new Font("Monospaced", Font.PLAIN, fontSize));
        FontMetrics fm = g.getFontMetrics();
        g.drawString(s, (x * cellSize), (y * cellSize) + fm.getHeight());
    }
    
    public KeyListener getKeyAdapter()
    {
        return new KeyAdapter() {
            private char[] numbers = "0123456789".toCharArray();
            
            @Override
            public void keyPressed(KeyEvent e)
            {
                if (KEYLISTENER_ENABLED)
                {
                    if (Arrays.binarySearch(numbers, e.getKeyChar()) >= 0)
                    {
                        short newCellSize = (short) SIZES[Character.digit(e.getKeyChar(), 10)];
                        if (newCellSize > 0 && newCellSize != cellSize)
                        {
                            Logger.log("cellSize: " + newCellSize);
                            setCellSize(newCellSize);
                        }
                    }
                }
            }
        };
    }
}
